package org.linkerproject.setting;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;

import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;

/**
 * 这个类是用来管理树状的信息存储到xml文件，以及从xml文件中读出信息.
 * 
 * 需要的参数是，这个信息名字，以及文件所保存的位置。
 */

public class SettingFile extends Object {

	/**
	 * 通过赋予信息的概括名字和文件的地址，读出xml文件所包含的树状信息.
	 * 
	 * （如果信息概括名字为空，则赋值为“setting”。）
	 * 
	 * @param name
	 *            信息的概括名字
	 * @param paraPath
	 *            信息文件的位置
	 */
	public SettingFile(final String paraName, final String paraPath) {
		this.filePath = paraPath;
		String name = paraName;

		if (name == null) {
			name = "html";
		}

		SAXBuilder builder = new SAXBuilder();
		try {
			document = builder.build(new File(paraPath));
		} catch (JDOMException e) {
			Element element = new Element(name);
			document = new Document(element);
		} catch (IOException e) {
			Element element = new Element(name);
			document = new Document(element);
		}
	}

	public Document getDocument() {
		return document;
	}

	/**
	 * 删除信息树上所指明的路径，包括其下面所有的分支.
	 * 
	 * @param address
	 *            信息树上所指明的路径。
	 */
	public final void deleteValue(final String address) {
		String name;
		String url = address;
		Element path = document.getRootElement();
		Element element;
		int firstPoint = url.indexOf(".");

		while (firstPoint > 0) {
			name = url.substring(0, firstPoint);

			element = path.getChild(name);
			if (element == null) {
				return;
			} else {
				path = element;
			}

			url = url.substring(firstPoint + 1);
			firstPoint = url.indexOf(".");
		}

		element = path.getChild(url);
		if (element == null) {
			return;
		}
		path.removeContent(element);
	}

	/**
	 * 获得信息树末梢的布尔类型，给它的参数是树的地址，比如"accounts.account.host"。它会自动寻
	 * 找到信息树那个分支的信息，并返回它的布尔值。如果保存的是其他值则无效.
	 * 
	 * @param address
	 *            信息是在树状结构中的位置。
	 * @return 信息树在所标识的位置返回的布尔值。
	 */
	public final Boolean getBooleanValue(final String address) {
		return Boolean.valueOf(getValue(address));
	}

	/**
	 * 获得信息树上所指明路径节点的根数目。比如，共有"accounts.account0","accounts.account1",
	 * "accounts.account2"。则节点"accounts"的返回的数目为3.
	 * 
	 * @param address
	 *            信息树上的路径。
	 * @return 返回信息树上所指明路径所包含的子节点数目。
	 */
	public int getElementSize(final String address) {
		String name;
		String url = address;
		Element path = document.getRootElement();
		Element element;
		int firstPoint = url.indexOf(".");

		while (firstPoint > 0) {
			name = url.substring(0, firstPoint);

			element = path.getChild(name);
			if (element == null) {
				return 0;
			} else {
				path = element;
			}

			url = url.substring(firstPoint + 1);
			firstPoint = url.indexOf(".");
		}

		element = path.getChild(url);
		if (element == null) {
			return 0;
		} else {
			return element.getChildren().size();
		}
	}

	public Element getElement(final String address) {
		String name;
		String url = address;
		Element path = document.getRootElement();
		Element element;
		int firstPoint = url.indexOf(".");

		while (firstPoint > 0) {
			name = url.substring(0, firstPoint);

			element = path.getChild(name);
			if (element == null) {
				return null;
			} else {
				path = element;
			}

			url = url.substring(firstPoint + 1);
			firstPoint = url.indexOf(".");
		}

		element = path.getChild(url);
		return element;
	}

	public ArrayList<Element> getChildren(final String address) {
		String name;
		String url = address;
		Element path = document.getRootElement();
		Element element;
		int firstPoint = url.indexOf(".");

		while (firstPoint > 0) {
			name = url.substring(0, firstPoint);

			element = path.getChild(name);
			if (element == null) {
				return null;
			} else {
				path = element;
			}

			url = url.substring(firstPoint + 1);
			firstPoint = url.indexOf(".");
		}

		element = path.getChild(url);
		if (element == null) {
			return null;
		} else {
			ArrayList<Element> es = new ArrayList<Element>();
			for (Object o : element.getChildren()) {
				if (o instanceof Element) {
					es.add((Element) o);
				}
			}
			return es;
		}
	}

	/**
	 * 获得信息树中所指位置的保存信息。比如"accounts.account0.host"，返回"gmail.com".
	 * 
	 * @param address
	 *            信息树中的位置。
	 * @return 信息树中所指位置返回的值。
	 */
	public final String getValue(final String address) {
		String name;
		String url = address;
		Element path = document.getRootElement();
		Element element;
		int firstPoint = url.indexOf(".");

		// 循环解析地址。
		while (firstPoint > 0) {
			name = url.substring(0, firstPoint);

			element = path.getChild(name);
			if (element == null) {
				return null;
			} else {
				path = element;
			}

			url = url.substring(firstPoint + 1);
			firstPoint = url.indexOf(".");
		}

		element = path.getChild(url);
		if (element == null) {
			return null;
		} else {
			return element.getText();
		}
	}

	public void save() {
		XMLOutputter outputer = new XMLOutputter(Format.getPrettyFormat());
		try {
			outputer.output(document, new FileOutputStream(filePath));
			System.out.println(filePath + "saved");
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}

	}

	/**
	 * 改变信息树上所指位置的值。当没有这条路径存在的时候，则会被建立.
	 * 
	 * @param address
	 *            信息树上的路径。
	 * @param value
	 *            所需要保存和建立的值。
	 */
	public final void setValue(final String address, final String value) {
		String name;
		String url = address;
		Element path = document.getRootElement();
		Element element;
		int firstPoint = url.indexOf(".");

		while (firstPoint > 0) {
			name = url.substring(0, firstPoint);

			element = path.getChild(name);
			if (element == null) {
				Element add = new Element(name);
				path.addContent(add);
				path = add;
			} else {
				path = element;
			}

			url = url.substring(firstPoint + 1);
			firstPoint = url.indexOf(".");
		}

		element = path.getChild(url);
		if (element == null) {
			element = new Element(url);
			path.addContent(element);
		}
		element.setText(value);
	}

	/**
	 * 信息树在程序内所保存的形式。由jdom包支持.
	 */
	private Document document;

	/**
	 * 信息文件所在的路径.
	 */
	private String filePath;

}
